package bz.ziro.kanbe.logic;

import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.slim3.datastore.Datastore;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.google.appengine.api.datastore.Key;

import bz.ziro.kanbe.bean.PageTreeData;
import bz.ziro.kanbe.dao.PageDao;
import bz.ziro.kanbe.model.Page;

/**
 * ページツリー作成ロジック
 * @author Administrator
 */
public class PageTreeLogic {

    //@SuppressWarnings("unused")
    private static final Logger logger = Logger.getLogger(PageTreeLogic.class.getName());


    /**
     * ツリーデータの作成
     * @return
     */
    public static PageTreeData createTreeData(Long siteKey) {
        //サイト内の全件データを取得
        List<Page> allPageList = PageDao.all(siteKey);
        //メンバに設定する
        PageTreeData rootObj = createTreeData(allPageList);
        return rootObj;
    }

    /**
     * ツリーデータ生成
     * @param rootPage
     * @param allPageList
     * @return
     */
    private static PageTreeData createTreeData(List<Page> allPageList) {

        Map<Key,Page> keyMap = new HashMap<Key,Page>();
        //一旦キーでページを登録
        for ( Page page : allPageList ) {
            keyMap.put(page.getKey(), page);
        }

        //すべてデータから、親が同一のオブジェクトをマップに作成する
        Map<Page,List<Page>> pageMap = new HashMap<Page,List<Page>>();

        Page root = null;
        //全頁データ数回回す
        for ( Page page : allPageList ) {
            //親ページの取得
            Key parentPageKey = page.getParentPageKey();
            //一番上のデータは処理しない
            if ( parentPageKey == null ) {
                root = page;
                continue;
            }

            Page parentPage = keyMap.get(parentPageKey);
            //同じ親のデータを取得
            List<Page> childList = pageMap.get(parentPage);

            //まだ存在しない場合
            if ( childList == null ) {
                childList = new ArrayList<Page>();
                //生成してマップに追加
                pageMap.put(parentPage,childList);
            }
            Page wkPage = keyMap.get(page.getKey());
            //頁を子リストに追加
            childList.add(wkPage);
        }

        //存在しなかった場合
        if ( root == null ) {
            return null;
        } else {
            root.setPriority(1);
            Datastore.put(root);
        }

        //優先順位がついてない場所を見つける
        Set<Entry<Page,List<Page>>> entrySet = pageMap.entrySet();
        Iterator<Entry<Page,List<Page>>> iter =  entrySet.iterator();
        while ( iter.hasNext() ) {
            Entry<Page,List<Page>> entry = iter.next();
            List<Page> pageList = entry.getValue();
            PageDao.updatePriority(pageList);
            Collections.sort(pageList, new PriorityComparator());
        }

        PageTreeData rootPage = new PageTreeData();
        //頁データを設定する
        rootPage.setPageList(root,pageMap);

        return rootPage;
    }

    /**
     * 優先順位により並び替え
     * @author Administrator
     *
     */
    static private class PriorityComparator implements Comparator<Page> {
        @Override
        public int compare(Page page1, Page page2) {
            return page2.getPriority().compareTo(page1.getPriority());
        }
    }

    /**
     * XML文字列から属性マップを作製
     * @param aXmlData
     * @return
     */
    public static void updateTree(Long siteKey,String aXmlData) {

        //サイト内の全件データを取得
        List<Page> allPageList = PageDao.all(siteKey);

        Map<Long,Page> keyMap = new HashMap<Long,Page>();
        //一旦キーでページを登録
        for ( Page page : allPageList ) {
            keyMap.put(page.getKey().getId(), page);
        }

        // ドキュメントビルダーファクトリを生成
        DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
        try {
            // ドキュメントビルダーを生成
            DocumentBuilder builder = dbfactory.newDocumentBuilder();
            // パースを実行してDocumentオブジェクトを取得
            Document doc = builder.parse(new ByteArrayInputStream(aXmlData.getBytes("UTF-8")));

            Element root = doc.getDocumentElement();
            String keyBuf = root.getAttribute("key");
            Page page = keyMap.get(Long.valueOf(keyBuf));

            //データ更新を呼び出す
            updateTree(root,page,keyMap);

        } catch (Exception ex) {
        	logger.warning(ex.getMessage());
            return;
        }
        Datastore.put(allPageList);

        return;
    }


    /**
     * 再帰関数
     * @param aElm
     * @param aPage
     * @param keyMap
     * @param updateList
     */
    private static void updateTree(Element aElm,Page aPage,Map<Long, Page> keyMap) {

        //ページデータを取得
        NodeList paramList = aElm.getChildNodes();
        int leng = paramList.getLength();

        int priority = 1;
        //属性数回繰り返す
        for ( int cnt = leng-1; cnt >= 0; --cnt ) {

            Node dataNode = paramList.item(cnt);

            if ( dataNode.getNodeType() != Node.ELEMENT_NODE ) continue;

            Element dataElm = (Element)dataNode;
            String keyVal = dataElm.getAttribute("key");

            //マップを取得
            Page page = keyMap.get(Long.valueOf(keyVal));
            //親を変更
            page.setParentPageKey(aPage.getKey());
            //優先順位を変更
            page.setPriority(priority);
            ++priority;

            //再帰で呼び出す
            updateTree(dataElm,page,keyMap);
        }
    }
}
